<?php
/**
 * Celebrio FileSystem module
 *
 * @copyright  Copyright (c) 2011 Celebrio Software
 * @package    Celebrio
 * @subpackage FileSystem
 */
namespace Celebrio\FileSystem;

use Nette\Object;

/**
 * Albireo class simplyfing work with a folder
 *
 * @author     Albireo Solutions
 */
class Folder extends Object {

    private $folder_url;

    /**
     * Create an object attached to a folder
     * @param String $folder_url path to the folder
     * @param boolean $create_if_doesnt_exist create the folder if it doesn't exist
     * @param octal $mode access mode for a new folder (if $create_if_doesnt_exist is set TRUE)
     * @return mixed the object or null
     * @throws FolderNotFoundException
     * @throws FolderException
     */
    public function __construct($folder_url, $create_if_doesnt_exist = FALSE, $mode = 0777) {
        if (!file_exists($folder_url) && $create_if_doesnt_exist === TRUE) {
            if (!@mkdir($folder_url, $mode, TRUE)) { // we create them recursively
                throw new FolderNotFoundException(sprintf(_("Folder %s not found and could not be created."), realpath($folder_url)));
                return NULL;
            }
        }
        if (!file_exists($folder_url)) {
            throw new FolderNotFoundException(sprintf(_("Folder %s not found."), realpath($folder_url)));
            return NULL;
        }
        if (!is_dir($folder_url)) {
            throw new FolderException(sprintf(_("%s is not a folder."), realpath($folder_url)));
            return NULL;
        }
        $this->folder_url = $folder_url;
    }

    /**
     * gets a content of the folder as an array sorted alphabeticaly
     * @param enum $order ASC or DESC - ascending or descending order
     * @param boolean $without_links_to_this_and_upper_folder removes . and .. if set TRUE
     * @return mixed Returns an array on success or NULL on failure.
     */
    public function getContent($order = "ASC", $without_links_to_this_and_upper_folder = TRUE) {
        if (!file_exists($this->folder_url)) {
            throw new FolderNotFoundException(sprintf(_("Folder %s not found."), realpath($this->folder_url)));
            return NULL;
        }
        if (strtoupper($order) == "ASC") {
            $folder_content = scandir($this->folder_url, 0); // the order is alphabetical in ascending order
        } elseif (strtoupper($order) == "DESC") {
            $folder_content = scandir($this->folder_url, 1); // the order is alphabetical in descending order
        } else {
            throw new FolderUnknownOrder(sprintf(_("It is not possible to choose %s order."), $order));
            return NULL;
        }
        if ($without_links_to_this_and_upper_folder === TRUE) {
            unset($folder_content [0], $folder_content [1]);
        }
        return $folder_content;
    }

    /**
     * delete the folder
     * @param boolean $recursive We delete the folder including it's content if $recursive is set TRUE.
     * @return boolean Returns TRUE on success or FALSE on failure.
     */
    public function delete($recursive = FALSE) {
        if (file_exists($this->folder_url)) {
            if ($recursive === FALSE) {
                return @rmdir($this->folder_url);
            } else {
                return $this->rrmdir($this->folder_url);
            }
        } else {
            return TRUE;
        }
    }

    /*
     * Function for recursive delete in $this->delete() function
     *
     * @param String directory to delete
     */

    //TODO: check this function if its totaly right and save
    private function rrmdir($dir) {
        if (is_dir($dir)) {
            $objects = scandir($dir);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (filetype($dir . "/" . $object) == "dir")
                        $this->rrmdir($dir . "/" . $object); else
                        unlink($dir . "/" . $object);
                }
            }
            reset($objects);
            rmdir($dir);
            return true;
        } else {
            return false;
        }
    }

    /*
     * get absolute path to the folder
     *
     * @return String folder url
     * @throws FolderNotFoundException
     */

    public function getFolderURL() {
        if (!file_exists($this->folder_url)) {
            throw new FolderNotFoundException(sprintf(_("Folder %s not found."), $this->folder_url));
        }
        return realpath($this->folder_url);
    }

    /*
     * Copy one folder to another recursively. BEWARE, url of this folder
     * is changing while cycling. After copy is better to call new Folder.
     *
     * @param string $destination url 
     */

    public function copy($destination) {
        @mkdir($destination);
        $content = $this->getContent();
        $source = $this->getFolderURL();
        foreach ($content as $entity) {
            if ($entity == null)
                break;
            if (is_file($source . \DIRECTORY_SEPARATOR . $entity)) {
                @copy($source . \DIRECTORY_SEPARATOR . $entity, $destination . \DIRECTORY_SEPARATOR . $entity);
            } elseif (is_dir($source . \DIRECTORY_SEPARATOR . $entity)) {
                $this->folder_url = $source . \DIRECTORY_SEPARATOR . $entity;
                $this->copy($destination . \DIRECTORY_SEPARATOR . $entity);
            }
        }
        $this->folder_url = $source; //cleaning up
    }

    /**
     * Moves the directory to the required destination. This method
     * provides the same functionality as rename() would (since renaming
     * and moving is the same action, see mv in UNIX shell).
     * 
     * @param String $destination the destination URL (with name in case 
     *        we split URL from name).
     */
    public function move($destination) {

        $newFolderParent = new Folder(dirname($destination), TRUE);
        rename($this->getFolderURL(), $destination);
    }
    
    public function getFolderName() {
        $path = $this->getFolderURL();
      
        $exploded = \explode("/", $path);
        $name = $exploded[count($exploded)-1];
        return $name;
    }

}